<script>
  import JsonString from './types/json-string.vue'
  import JsonUndefined from './types/json-undefined.vue'
  import JsonNumber from './types/json-number.vue'
  import JsonBoolean from './types/json-boolean.vue'
  import JsonObject from './types/json-object.vue'
  import JsonArray from './types/json-array.vue'
  import JsonFunction from './types/json-function.vue'
  import JsonDate from './types/json-date.vue'
  import { h } from 'vue'
  export default {
    name: 'JsonBox',
    inject: ['expandDepth'],
    props: {
      value: {
        type: [Object, Array, String, Number, Boolean, Function, Date],
        default: null,
      },
      keyName: {
        type: String,
        default: '',
      },
      sort: Boolean,
      depth: {
        type: Number,
        default: 0,
      },
      previewMode: Boolean,
    },
    data() {
      return {
        expand: true,
      }
    },
    mounted() {
      this.expand = this.previewMode || this.depth < this.expandDepth
    },
    methods: {
      toggle() {
        this.expand = !this.expand

        try {
          this.$el.dispatchEvent(new Event('resized'))
        } catch (e) {
          // handle IE not supporting Event constructor
          const evt = document.createEvent('Event')
          evt.initEvent('resized', true, false)
          this.$el.dispatchEvent(evt)
        }
      },
    },
    render() {
      let elements = []
      let dataType

      if (this.value === null || this.value === undefined) {
        dataType = JsonUndefined
      } else if (Array.isArray(this.value)) {
        dataType = JsonArray
      } else if (
        Object.prototype.toString.call(this.value) === '[object Date]'
      ) {
        dataType = JsonDate
      } else if (typeof this.value === 'object') {
        dataType = JsonObject
      } else if (typeof this.value === 'number') {
        dataType = JsonNumber
      } else if (typeof this.value === 'string') {
        dataType = JsonString
      } else if (typeof this.value === 'boolean') {
        dataType = JsonBoolean
      } else if (typeof this.value === 'function') {
        dataType = JsonFunction
      }
      const complex =
        this.keyName &&
        this.value &&
        (Array.isArray(this.value) ||
          (typeof this.value === 'object' &&
            Object.prototype.toString.call(this.value) !== '[object Date]'))

      if (!this.previewMode && complex) {
        elements.push(
          h('span', {
            class: {
              'jv-toggle': true,
              open: !!this.expand,
            },
            onClick: this.toggle,
          })
        )
      }

      if (this.keyName) {
        elements.push(
          h('span', {
            class: {
              'jv-key': true,
            },
            innerText: `${this.keyName}:`,
          })
        )
      }

      elements.push(
        h(dataType, {
          class: {
            'jv-push': true,
          },
          jsonValue: this.value,
          keyName: this.keyName,
          sort: this.sort,
          depth: this.depth,
          expand: this.expand,
          previewMode: this.previewMode,
          'onUpdate:expand': (value) => {
            this.expand = value
          },
        })
      )

      return h(
        'div',
        {
          class: {
            'jv-node': true,
            'jv-key-node': Boolean(this.keyName) && !complex,
            toggle: !this.previewMode && complex,
          },
        },
        elements
      )
    },
  }
</script>

<style>
  .jv-node {
    position: relative;
  }
  .jv-node:after {
    content: ',';
  }
  .jv-node:last-of-type:after {
    content: '';
  }
  .jv-node.toggle {
    margin-left: 13px !important;
  }
  .jv-node .jv-node {
    margin-left: 25px;
  }
</style>
